home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / state.c < prev    next >
C/C++ Source or Header  |  2000-04-23  |  16KB  |  634 lines

  1. /* State save/load functions */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <ctype.h>
  6. #include <stdarg.h>
  7. #include "osd_cpu.h"
  8. #include "memory.h"
  9. #include "mamedbg.h"
  10. #include "osdepend.h"
  11. #include "state.h"
  12. #include "mame.h"
  13.  
  14.  
  15. /* A forward linked list of the contents of a section */
  16. typedef struct tag_state_var {
  17.     struct tag_state_var *next;
  18.     char *name;
  19.     unsigned size;
  20.     unsigned chunk;
  21.     void *data;
  22. }   state_var;
  23.  
  24. /* Our state handling structure */
  25. typedef struct {
  26.     void *file;
  27.     const char *cur_module;
  28.     int cur_instance;
  29.     state_var *list;
  30. }   state_handle;
  31.  
  32. INLINE unsigned xtoul(char **p, int *size)
  33. {
  34.     unsigned val = 0, digit;
  35.  
  36.     if (size) *size = 0;
  37.     while( isxdigit(**p) )
  38.     {
  39.         digit = toupper(**p) - '0';
  40.         if( digit > 9 ) digit -= 7;
  41.         val = (val << 4) | digit;
  42.         if( size ) (*size)++;
  43.         *p += 1;
  44.     }
  45.     while( isspace(**p) ) *p += 1;
  46.     if (size) (*size) >>= 1;
  47.     return val;
  48. }
  49.  
  50. INLINE char *ultox(unsigned val, unsigned size)
  51. {
  52.     static char buffer[32+1];
  53.     static char digit[] = "0123456789ABCDEF";
  54.     char *p = &buffer[size];
  55.     *p-- = '\0';
  56.     while( size-- > 0 )
  57.     {
  58.         *p-- = digit[val & 15];
  59.         val >>= 4;
  60.     }
  61.     return buffer;
  62. }
  63.  
  64. /**************************************************************************
  65.  * my_stricmp
  66.  * Compare strings case insensitive
  67.  **************************************************************************/
  68. INLINE int my_stricmp( const char *dst, const char *src)
  69. {
  70.     while( *src && *dst )
  71.     {
  72.         if( tolower(*src) != tolower(*dst) ) return *dst - *src;
  73.         src++;
  74.         dst++;
  75.     }
  76.     return *dst - *src;
  77. }
  78.  
  79. /* free a linked list of state_vars (aka section) */
  80. void state_free_section( void *s )
  81. {
  82.     state_handle *state = (state_handle *)s;
  83.     state_var *v1, *v2;
  84.     v2 = state->list;
  85.     while( v2 )
  86.     {
  87.         if( v2->name ) free( v2->name );
  88.         if( v2->data ) free( v2->data );
  89.         v1 = v2;
  90.         v2 = v2->next;
  91.         free( v1 );
  92.     }
  93.     state->list = NULL;
  94. }
  95.  
  96. void *state_create(const char *name)
  97. {
  98.     state_handle *state;
  99.     state = (state_handle *) malloc( sizeof(state_handle) );
  100.     if( !state ) return NULL;
  101.     state->cur_module = NULL;
  102.     state->cur_instance = 0;
  103.     state->list = NULL;
  104.     state->file = osd_fopen( name, NULL, OSD_FILETYPE_STATE, 1 );
  105.     if( !state->file )
  106.     {
  107.         free(state);
  108.         return NULL;
  109.     }
  110.     return state;
  111. }
  112.  
  113. void *state_open(const char *name)
  114. {
  115.     state_handle *state;
  116.     state = (state_handle *) malloc( sizeof(state_handle) );
  117.     if( !state ) return NULL;
  118.     state->cur_module = NULL;
  119.     state->cur_instance = 0;
  120.     state->list = NULL;
  121.     state->file = osd_fopen( name, NULL, OSD_FILETYPE_STATE, 0 );
  122.     if( !state->file )
  123.     {
  124.         free(state);
  125.         return NULL;
  126.     }
  127.     return state;
  128. }
  129.  
  130. void state_close( void *s )
  131. {
  132.     state_handle *state = (state_handle *)s;
  133.     if( !state ) return;
  134.     state_free_section( state );
  135.     if( state->file ) osd_fclose( state->file );
  136.     free( state );
  137. }
  138.  
  139. /* Output a formatted string to the state file */
  140. static void CLIB_DECL emit(void *s, const char *fmt, ...)
  141. {
  142.     static char buffer[128+1];
  143.     state_handle *state = (state_handle *)s;
  144.     va_list arg;
  145.     int length;
  146.  
  147.     va_start(arg,fmt);
  148.     length = vsprintf(buffer, fmt, arg);
  149.     va_end(arg);
  150.  
  151.     if( osd_fwrite(state->file, buffer, length) != length )
  152.     {
  153.         logerror("emit: Error while saving state '%s'\n", buffer);
  154.     }
  155. }
  156.  
  157. void state_save_section( void *s, const char *module, int instance )
  158. {
  159.     state_handle *state = (state_handle *)s;
  160.     if( !state->cur_module ||
  161.         (state->cur_module && my_stricmp(state->cur_module, module)) ||
  162.         state->cur_instance != instance )
  163.     {
  164.         if( state->cur_module )
  165.             emit(state,"\n");
  166.         state->cur_module = module;
  167.         state->cur_instance = instance;
  168.         emit(state,"[%s.%d]\n", module, instance);
  169.     }
  170. }
  171.  
  172. void state_save_UINT8( void *s, const char *module,int instance,
  173.     const char *name, const UINT8 *val, unsigned size )
  174. {
  175.     state_handle *state = (state_handle *)s;
  176.  
  177.     state_save_section( state, module, instance );
  178.  
  179.     /* If this is to much for a single line use the dump format */
  180.     if( size > 16 )
  181.     {
  182.         unsigned offs = 0;
  183.         while( size-- > 0 )
  184.         {
  185.             if( (offs & 15 ) == 0 )
  186.                 emit( state, "%s.%s=", name, ultox(offs,4) );
  187.             emit( state, "%s", ultox(*val++,2) );
  188.             if( (++offs & 15) == 0)
  189.                 emit( state, "\n" );
  190.             else
  191.                 emit( state, " " );
  192.         }
  193.         if( offs & 15 ) emit( state, "\n" );
  194.     }
  195.     else
  196.     {
  197.         emit( state, "%s=", name );
  198.         while( size-- > 0 )
  199.         {
  200.             emit( state, "%s", ultox(*val++,2) );
  201.             if( size ) emit( state, " " );
  202.         }
  203.         emit( state, "\n" );
  204.     }
  205. }
  206.  
  207. void state_save_INT8( void *s, const char *module,int instance,
  208.     const char *name, const INT8 *val, unsigned size )
  209. {
  210.     state_save_UINT8( s, module, instance, name, (UINT8*)val, size );
  211. }
  212.  
  213. void state_save_UINT16(void *s, const char *module,int instance,
  214.     const char *name, const UINT16 *val, unsigned size)
  215. {
  216.     state_handle *state = (state_handle *)s;
  217.  
  218.     state_save_section( state, module, instance );
  219.  
  220.     /* If this is to much for a single line use the dump format */
  221.     if( size > 8 )
  222.     {
  223.         unsigned offs = 0;
  224.         while( size-- > 0 )
  225.         {
  226.             if( (offs & 7 ) == 0 )
  227.                 emit( state, "%s.%s=", name, ultox(offs,4) );
  228.             emit( state, "%s", ultox(*val++,4) );
  229.             if( (++offs & 7) == 0)
  230.                 emit( state, "\n" );
  231.             else
  232.                 emit( state, " " );
  233.         }
  234.         if( offs & 7 ) emit( state, "\n" );
  235.     }
  236.     else
  237.     {
  238.         emit( state, "%s=", name );
  239.         while( size-- > 0 )
  240.         {
  241.             emit( state, "%s", ultox(*val++,4) );
  242.             if( size ) emit( state, " " );
  243.         }
  244.         emit( state, "\n" );
  245.     }
  246. }
  247.  
  248. void state_save_INT16( void *s, const char *module,int instance,
  249.     const char *name, const INT16 *val, unsigned size )
  250. {
  251.     state_save_UINT16( s, module, instance, name, (UINT16*)val, size );
  252. }
  253.  
  254. void state_save_UINT32( void *s, const char *module,int instance,
  255.     const char *name, const UINT32 *val, unsigned size )
  256. {
  257.     state_handle *state = (state_handle *)s;
  258.  
  259.     state_save_section( state, module, instance );
  260.  
  261.     /* If this is to much for a single line use the dump format */
  262.     if( size > 4 )
  263.     {
  264.         unsigned offs = 0;
  265.         while( size-- > 0 )
  266.         {
  267.             if( (offs & 3 ) == 0 )
  268.                 emit( state, "%s.%s=", name, ultox(offs,4) );
  269.             emit( state, "%s", ultox(*val++,8) );
  270.             if( (++offs & 3) == 0)
  271.                 emit( state, "\n" );
  272.             else
  273.                 emit( state, " " );
  274.         }
  275.         if( offs & 3 ) emit( state, "\n" );
  276.     }
  277.     else
  278.     {
  279.         emit( state, "%s=", name );
  280.         while( size-- > 0 )
  281.         {
  282.             emit( state, "%s", ultox(*val++,8) );
  283.             if( size ) emit( state, " " );
  284.         }
  285.         emit( state, "\n" );
  286.     }
  287. }
  288.  
  289. void state_save_INT32( void *s, const char *module,int instance,
  290.     const char *name, const INT32 *val, unsigned size )
  291. {
  292.     state_save_UINT32( s, module, instance, name, (UINT32*)val, size );
  293. }
  294.  
  295. /* load a linked list of state_vars (aka section) */
  296. void state_load_section( void *s, const char *module, int instance )
  297. {
  298.     state_handle *state = (state_handle *)s;
  299.  
  300.     /* Make the buffer twice as big as it was while saving
  301.        the state, so we should always catch a [section] */
  302.  
  303.     static char buffer[256+1];
  304.     char section[128+1], *p, *d;
  305.     int length, element_size, rewind_file = 1;
  306.     unsigned offs, data;
  307.  
  308.     if( state->cur_module &&
  309.         !my_stricmp(state->cur_module, module) &&
  310.         state->cur_instance == instance )
  311.         return; /* fine, we already got it */
  312.  
  313.     if( !state->list )
  314.         state_free_section(state);
  315.  
  316.     sprintf(section, "[%s.%d]", module, instance);
  317.  
  318.     for( ; ; )
  319.     {
  320.         length = osd_fread(state->file, buffer, sizeof(buffer) - 1);
  321.         if( length <= 0 )
  322.         {
  323.             if( rewind_file )
  324.             {
  325.                 logerror("state_load_section: Section '%s' not found\n", section);
  326.                 return;
  327.             }
  328.  
  329.             rewind_file = 0;
  330.             osd_fseek(state->file, 0, SEEK_SET);
  331.             length = osd_fread(state->file, buffer, sizeof(buffer) - 1);
  332.             if( length <= 0 )
  333.             {
  334.                 logerror("state_load_section: Truncated state while loading state '%s'\n", section);
  335.                 return;
  336.             }
  337.         }
  338.         buffer[ length ] = '\0';
  339.         p = strchr(buffer, '[');
  340.         if( p && !my_stricmp(p, section) )
  341.         {
  342.             /* skip CR, LF or both */
  343.             p += strlen(section);
  344.             if( *p == '\r' || *p == '\n' ) p++; /* skip CR or LF */
  345.             if( *p == '\r' || *p == '\n' ) p++; /* in any order */
  346.             state->cur_module = module;
  347.             state->cur_instance = instance;
  348.             /* now read all state_vars until the next section or end of state */
  349.             for( ; ; )
  350.             {
  351.                 state_var *v;
  352.  
  353.                 /* seek back to the end of line state position */
  354.                 osd_fseek( state->file, (int)(p - &buffer[length]), SEEK_CUR );
  355.  
  356.                 length = osd_fread( state->file, buffer, sizeof(buffer) - 1 );
  357.  
  358.                 if( length <= 0 )
  359.                     return;
  360.                 buffer[ length ] = '\0';
  361.  
  362.                 p = strchr(buffer, '\n');
  363.                 if( !p ) p = strchr(buffer, '\r');
  364.                 if( !p )
  365.                 {
  366.                     logerror("state_load_section: Line to long in section '%s'\n", section);
  367.                     return;
  368.                 }
  369.  
  370.                 *p = '\0';                  /* cut buffer here */
  371.                 p = strchr(buffer, '\n');   /* do we still have a CR? */
  372.                 if( p ) *p = '\0';
  373.                 p = strchr(buffer, '\r');   /* do we still have a LF? */
  374.                 if( p ) *p = '\0';
  375.  
  376.  
  377.                 if( *buffer == '[' )        /* next section ? */
  378.                     return;
  379.  
  380.                 if( *buffer == '\0' ||      /* empty line or comment ? */
  381.                     *buffer == '#' ||
  382.                     *buffer == ';' )
  383.                     continue;
  384.  
  385.                 /* find the state_var data */
  386.                 p = strchr(buffer, '=');
  387.                 if( !p )
  388.                 {
  389.                     logerror("state_load_section: Line contains no '=' character\n");
  390.                     return;
  391.                 }
  392.  
  393.                 /* buffer = state_var[.offs], p = data */
  394.                 *p++ = '\0';
  395.  
  396.                 /* is there an offs defined ? */
  397.                 d = strchr(buffer, '.');
  398.                 if( d )
  399.                 {
  400.                     /* buffer = state_var, d = offs, p = data */
  401.                     *d++ = '\0';
  402.                     offs = xtoul(&d,NULL);
  403.                     if( offs )
  404.                     {
  405.                         v = state->list;
  406.                         while( v && my_stricmp(v->name, buffer) )
  407.                             v = v->next;
  408.                         if( !v )
  409.                         {
  410.                             logerror("state_load_section: Invalid variable continuation found '%s.%04X'\n", buffer, offs);
  411.                             return;
  412.                         }
  413.                     }
  414.                 }
  415.                 else
  416.                 {
  417.                     offs = 0;
  418.                 }
  419.  
  420.                 if( state->list )
  421.                 {
  422.                     /* next state_var */
  423.                     v = state->list;
  424.                     while( v->next ) v = v->next;
  425.                     v->next = malloc( sizeof(state_var) );
  426.                     v = v->next;
  427.                 }
  428.                 else
  429.                 {
  430.                     /* first state_var */
  431.                     state->list = malloc(sizeof(state_var));
  432.                     v = state->list;
  433.                 }
  434.                 if( !v )
  435.                 {
  436.                     logerror("state_load_section: Out of memory while reading '%s'\n", section);
  437.                     return;
  438.                 }
  439.                 v->name = malloc(strlen(buffer) + 1);
  440.                 if( !v->name )
  441.                 {
  442.                     logerror("state_load_section: Out of memory while reading '%s'\n", section);
  443.                     return;
  444.                 }
  445.                 strcpy(v->name, buffer);
  446.                 v->size = 0;
  447.                 v->data = NULL;
  448.  
  449.                 /* convert the line back into data */
  450.                 data = xtoul( &p, &element_size );
  451.                 do
  452.                 {
  453.                     v->size++;
  454.                     /* need to allocate first/next chunk of memory? */
  455.                     if( v->size * element_size >= v->chunk )
  456.                     {
  457.                         v->chunk += CHUNK_SIZE;
  458.                         if( v->data )
  459.                             v->data = realloc(v->data, v->chunk);
  460.                         else
  461.                             v->data = malloc(v->chunk);
  462.                     }
  463.                     /* check if the (re-)allocation failed */
  464.                     if( !v->data )
  465.                     {
  466.                         logerror("state_load_section: Out of memory while reading '%s'\n", section);
  467.                         return;
  468.                     }
  469.                     /* store element */
  470.                     switch( element_size )
  471.                     {
  472.                         case 1: *((UINT8*)v->data + v->size) = data;
  473.                         case 2: *((UINT16*)v->data + v->size) = data;
  474.                         case 4: *((UINT32*)v->data + v->size) = data;
  475.                     }
  476.                     data = xtoul( &p, NULL );
  477.                 } while( *p );
  478.             }
  479.         }
  480.         else
  481.         {
  482.             /* skip back a half buffer size */
  483.             osd_fseek( state->file, - (sizeof(buffer)-1) / 2, SEEK_CUR );
  484.         }
  485.     }
  486. }
  487.  
  488. void state_load_UINT8( void *s, const char *module, int instance,
  489.     const char *name, UINT8 *val, unsigned size )
  490. {
  491.     state_handle *state = (state_handle *)s;
  492.     state_var *v;
  493.  
  494.     state_load_section( state, module, instance );
  495.  
  496.     v = state->list;
  497.     while( v && my_stricmp(v->name, name) ) v = v->next;
  498.  
  499.     if( v )
  500.     {
  501.         unsigned offs;
  502.         for( offs = 0; offs < size && offs < v->size; offs++ )
  503.             *val++ = *((UINT8*)v->data + offs);
  504.     }
  505.     else
  506.     {
  507.         logerror("state_load_UINT8: variable '%s' not found in section [%s.%d]\n", name, module, instance);
  508.         memset(val, 0, size);
  509.     }
  510. }
  511.  
  512. void state_load_INT8( void *s, const char *module, int instance,
  513.     const char *name, INT8 *val, unsigned size )
  514. {
  515.     state_handle *state = (state_handle *)s;
  516.     state_var *v;
  517.  
  518.     state_load_section( state, module, instance );
  519.  
  520.     v = state->list;
  521.     while( v && my_stricmp(v->name, name) ) v = v->next;
  522.  
  523.     if( v )
  524.     {
  525.         unsigned offs;
  526.         for( offs = 0; offs < size && offs < v->size; offs++ )
  527.             *val++ = *((INT8*)v->data + offs);
  528.     }
  529.     else
  530.     {
  531.         logerror("state_load_INT8: variable '%s' not found in section [%s.%d]\n", name, module, instance);
  532.         memset(val, 0, size);
  533.     }
  534. }
  535.  
  536. void state_load_UINT16( void *s, const char *module, int instance,
  537.     const char *name, UINT16 *val, unsigned size )
  538. {
  539.     state_handle *state = (state_handle *)s;
  540.     state_var *v;
  541.  
  542.     state_load_section( state, module, instance );
  543.  
  544.     v = state->list;
  545.     while( v && my_stricmp(v->name, name) ) v = v->next;
  546.  
  547.     if( v )
  548.     {
  549.         unsigned offs;
  550.         for( offs = 0; offs < size && offs < v->size; offs++ )
  551.             *val++ = *((UINT16*)v->data + offs);
  552.     }
  553.     else
  554.     {
  555.         logerror("state_load_UINT16: variable '%s' not found in section [%s.%d]\n", name, module, instance);
  556.         memset(val, 0, size * 2);
  557.     }
  558. }
  559.  
  560. void state_load_INT16( void *s, const char *module, int instance,
  561.     const char *name, INT16 *val, unsigned size )
  562. {
  563.     state_handle *state = (state_handle *)s;
  564.     state_var *v;
  565.  
  566.     state_load_section( state, module, instance );
  567.  
  568.     v = state->list;
  569.     while( v && my_stricmp(v->name, name) ) v = v->next;
  570.  
  571.     if( v )
  572.     {
  573.         unsigned offs;
  574.         for( offs = 0; offs < size && offs < v->size; offs++ )
  575.             *val++ = *((INT16*)v->data + offs);
  576.     }
  577.     else
  578.     {
  579.         logerror("state_load_INT16: variable '%s' not found in section [%s.%d]\n", name, module, instance);
  580.         memset(val, 0, size * 2);
  581.     }
  582. }
  583.  
  584. void state_load_UINT32( void *s, const char *module, int instance,
  585.     const char *name, UINT32 *val, unsigned size )
  586. {
  587.     state_handle *state = (state_handle *)s;
  588.     state_var *v;
  589.  
  590.     state_load_section( state, module, instance );
  591.  
  592.     v = state->list;
  593.     while( v && my_stricmp(v->name, name) ) v = v->next;
  594.  
  595.     if( v )
  596.     {
  597.         unsigned offs;
  598.         for( offs = 0; offs < size && offs < v->size; offs++ )
  599.             *val++ = *((UINT32*)v->data + offs);
  600.     }
  601.     else
  602.     {
  603.         logerror("state_load_UINT32: variable'%s' not found in section [%s.%d]\n", name, module, instance);
  604.         memset(val, 0, size * 4);
  605.     }
  606. }
  607.  
  608. void state_load_INT32( void *s, const char *module, int instance,
  609.     const char *name, INT32 *val, unsigned size )
  610. {
  611.     state_handle *state = (state_handle *)s;
  612.     state_var *v;
  613.  
  614.     state_load_section( state, module, instance );
  615.  
  616.     v = state->list;
  617.     while( v && my_stricmp(v->name, name) ) v = v->next;
  618.  
  619.     if( v )
  620.     {
  621.         unsigned offs;
  622.         for( offs = 0; offs < size && offs < v->size; offs++ )
  623.             *val++ = *((INT32*)v->data + offs);
  624.     }
  625.     else
  626.     {
  627.         logerror("state_load_INT32: variable'%s' not found in section [%s.%d]\n", name, module, instance);
  628.         memset(val, 0, size * 4);
  629.     }
  630. }
  631.  
  632.  
  633.  
  634.